/*
 * Copyright © OpenAtom Foundation.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package io.iec.edp.caf.databaseobject;

import io.iec.edp.caf.databaseobject.api.exception.DboException;
import io.iec.edp.caf.databaseobject.common.DatabaseObjectCommonUtil;
import io.iec.edp.caf.databaseobject.common.cache.DatabaseObjectCacheManager;
import io.iec.edp.caf.databaseobject.common.database.GspDatabase;
import io.iec.edp.caf.databaseobject.common.database.GspDbFactory;
import io.iec.edp.caf.databaseobject.common.helper.SQLReflectHelper;
import io.iec.edp.caf.databaseobject.common.helper.TableNameHelper;
import io.iec.edp.caf.databaseobject.api.context.ReservedColumns;
import io.iec.edp.caf.databaseobject.api.entity.*;
import io.iec.edp.caf.databaseobject.common.DatabaseObjectCheckUtil;
import io.iec.edp.caf.databaseobject.manager.DatabaseObjectServiceImpl;
import io.iec.edp.caf.databaseobject.spi.ITableNameRuleManager;
import io.iec.edp.caf.databaseobject.sqlprovider.SqlProvider;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.annotations.common.util.StringHelper;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataBuilder;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.mapping.Index;
import org.hibernate.mapping.Table;
import org.hibernate.query.NativeQuery;
import org.hibernate.service.ServiceRegistry;

import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @author liu_wei
 */
@Slf4j
public class DboDeployManager {

    private String runtimePath;
    private DbType dbType;
    private StandardServiceRegistryBuilder serviceRegistryBuilder;
    private SessionFactory sessionFactory;
    private Metadata metadata;
    private DBInfo dbInfo;

    private List<String> dboClasses;
    private List<String> SqlList;
    private List<AbstractDatabaseObject> newDatabaseObjects;
    private List<AbstractDatabaseObject> newTable;
    private Map<String, List<ColumnChangeOperation>> columnChangeOperations;
    private Map<String, DatabaseObjectTable> columnChangedTables;
    private Map<String, String> views = null;

    /**
     * 部署指定目录下的Dbo
     *
     * @param dboPath       dbo路径
     * @param dimensionInfo 维度信息
     * @param dbInfo        数据库信息
     */
    public void deployDboList(String dboPath, Map<String, String> dimensionInfo, DBInfo dbInfo) {
        DatabaseObjectServiceImpl service = new DatabaseObjectServiceImpl();
        List<AbstractDatabaseObject> databaseObjects = service.getDatabaseObjectListRecursivly(dboPath);
        exeDbosDeploy(databaseObjects, dimensionInfo, dbInfo);
    }

    /**
     * 命令行调用部署入口
     *
     * @param dboPath        dbo路径
     * @param dimensionInfos 维度
     * @param dbInfo         数据库信息
     */
    public void deployDboWithDimensionList(String dboPath, Map<String, List<String>> dimensionInfos, DBInfo dbInfo) {
        DatabaseObjectServiceImpl service = new DatabaseObjectServiceImpl();
        List<AbstractDatabaseObject> databaseObjects = service.getDatabaseObjectListRecursivly(dboPath);

        List<Map<String, String>> list = new ArrayList<>();
        for (String key : dimensionInfos.keySet()) {
            list = getSingleMap(list, key, dimensionInfos.get(key));
        }

        beforeDeployInit(dbInfo);
        DatabaseObjectCommonUtil commonUtil = new DatabaseObjectCommonUtil();
        List<String> tables = commonUtil.getDbTables(dbInfo);
        //判断是否包含月度表
        List<AbstractDatabaseObject> monthDboList = databaseObjects.stream().filter(x -> x.getType() == DatabaseObjectType.Table && ((DatabaseObjectTable) x).getHasNameRule() && ((DatabaseObjectTable) x).getDboTableNameRule().getCode().equalsIgnoreCase("YYMM")).collect(Collectors.toList());
        if (monthDboList.size() > 0) {
            List<String> dboIds = monthDboList.stream().map(AbstractDatabaseObject::getId).collect(Collectors.toList());
            databaseObjects.removeIf(x -> dboIds.contains(x.getId()));
            monthDboDeployInit(monthDboList, tables);
        }
        for (Map<String, String> dimensionInfo : list) {
            dbosDeployInit(databaseObjects, dimensionInfo, tables);
        }
        dbosDeployExecute(dbInfo);
    }

    public void deployDboWithDimensionList(List<AbstractDatabaseObject> databaseObjects, Map<String, List<String>> dimensionInfos, DBInfo dbInfo) {
        List<Map<String, String>> list = new ArrayList<>();
        for (String key : dimensionInfos.keySet()) {
            list = getSingleMap(list, key, dimensionInfos.get(key));
        }
        beforeDeployInit(dbInfo);
        List<String> tables = new DatabaseObjectCommonUtil().getDbTables(dbInfo);
        //不带维度策略的DBO
        List<AbstractDatabaseObject> abstractDatabaseObjects = new ArrayList<>();
        //带维度策略的DBO
        List<AbstractDatabaseObject> dimensionDatabaseObjects = new ArrayList<>();
        for (AbstractDatabaseObject databaseObject : databaseObjects) {
            if (databaseObject.getType() == DatabaseObjectType.Table) {
                if (((DatabaseObjectTable) databaseObject).getHasNameRule()) {
                    dimensionDatabaseObjects.add(databaseObject);
                    continue;
                }
            } else if (databaseObject.getType() == DatabaseObjectType.View) {
                if (((DatabaseObjectView) databaseObject).getHasNameRule()) {
                    dimensionDatabaseObjects.add(databaseObject);
                    continue;
                }
            }
            abstractDatabaseObjects.add(databaseObject);
        }
        Map<String, String> dimension = new HashMap<>();
        dbosDeployInit(abstractDatabaseObjects, dimension, tables);
        for (Map<String, String> dimensionInfo : list) {
            dbosDeployInit(dimensionDatabaseObjects, dimensionInfo, tables);
        }
        dbosDeployExecute(dbInfo);
    }

    private List<Map<String, String>> getSingleMap(List<Map<String, String>> list, String key, List<String> values) {
        if (list.size() <= 0) {
            for (String value : values) {
                Map<String, String> dic = new HashMap<>();
                dic.put(key, value);
                list.add(dic);
            }
            return list;
        } else {
            List<Map<String, String>> result = new ArrayList<>();
            for (String value : values) {
                for (Map<String, String> dict : list) {
                    Map<String, String> sd = new HashMap<>();
                    sd.put(key, value);
                    for (String pair : dict.keySet()) {
                        sd.put(pair, dict.get(pair));
                        result.add(sd);
                    }
                }
            }
            return result;
        }
    }

    public DboDeployResultInfo deployDboList(List<AbstractDatabaseObject> databaseObjcts, Map<String, String> dimensionValue, DBInfo dbInfo) {
        DboDeployResultInfo resultInfo = new DboDeployResultInfo();
        resultInfo.setDeploySuccess(true);
        resultInfo.setDeployResult(new HashMap<>());
        exeDbosDeploy(databaseObjcts, dimensionValue, dbInfo);
        return resultInfo;
    }

    /**
     * 部署传入的Dbo对象
     *
     * @param databaseObject 数据库对象
     * @param dimensionInfo  维度信息
     * @param dbInfo         数据库信息
     */
    public void deployDbo(AbstractDatabaseObject databaseObject, Map<String, String> dimensionInfo, DBInfo dbInfo) {

        List<AbstractDatabaseObject> databaseObjects = new ArrayList<>();
        databaseObjects.add(databaseObject);
        exeDbosDeploy(databaseObjects, dimensionInfo, dbInfo);
    }

    /**
     * 执行DBO部署操作，运行时入口
     *
     * @param databaseObjects 数据库对象列表
     * @param dimensionInfo   维度信息
     * @param dbInfo          数据库信息
     */
    private void exeDbosDeploy(List<AbstractDatabaseObject> databaseObjects, Map<String, String> dimensionInfo, DBInfo dbInfo) {

        beforeDeployInit(dbInfo);
        dbosDeployInit(databaseObjects, dimensionInfo, null);
        dbosDeployExecute(dbInfo);
    }

    private void beforeDeployInit(DBInfo dbInfo) {
        dboClasses = new ArrayList<>();
        SqlList = new ArrayList<>();
        newDatabaseObjects = new ArrayList<>();
        newTable = new ArrayList<>();
        columnChangeOperations = new HashMap<String, List<ColumnChangeOperation>>();
        columnChangedTables = new HashMap<>();
        this.dbInfo = dbInfo;
        this.dbType = dbInfo.getDbType();
        applySetting();
        //initSessionFactory();
    }

    public Map<String, List<String>> getTempTablesCreateSql(List<AbstractDatabaseObject> databaseObjects, DBInfo info) {

        //指定编译路径，支持多线程部署
        String generatorPath = "";
        try {
            beforeDeployInit(info);
            initSessionFactory();
            DatabaseObjectCheckUtil checkUtil = new DatabaseObjectCheckUtil();
            for (AbstractDatabaseObject databaseObject : databaseObjects) {
                checkUtil.checkDatabaseObjectAvailable(databaseObject);
                if (databaseObject.getType() == DatabaseObjectType.TempTable) {
                    DatabaseObjectTable table = ((DatabaseObjectTable) databaseObject).clone();
                    String fileName = table.getCode() + UUID.randomUUID().toString().substring(0, 5);
                    dboClasses.add(fileName);
                    //将一组DBO中第一个文件名当做编译的文件夹
                    generatorPath = dboClasses.get(0);
                    deployDatabaseObject(table, fileName, generatorPath);
                    newDatabaseObjects.add(databaseObject);
                }
            }
            runtimePath = System.getProperty("user.dir");
            DboDeployFileService fileService = new DboDeployFileService();
            fileService.compile(newDatabaseObjects.get(0), dbType, dboClasses.get(0));
            fileService.loadClass(runtimePath, generatorPath);

            ServiceRegistry serviceRegistry = serviceRegistryBuilder.build();
            MetadataSources metadataSources = new MetadataSources(serviceRegistry);
            Collection<Table> tables = new ArrayList<>();
            for (String dboClass : dboClasses) {
                Class b = Class.forName("dbo." + dboClass);
                metadataSources.addAnnotatedClass(b);
            }
            MetadataBuilder metadataBuilder = metadataSources.getMetadataBuilder();
            DboPhysicalNamingStrategy dboPhysicalNamingStrategy =new DboPhysicalNamingStrategy();
            dboPhysicalNamingStrategy.setDbType(dbType);
            metadataBuilder.applyPhysicalNamingStrategy(dboPhysicalNamingStrategy);
            Metadata metadata = metadataBuilder.build();

            tables = metadata.getDatabase().getDefaultNamespace().getTables();
            Map<String, List<String>> sqlMap = new HashMap<>();
            for (Table table : tables) {
                String[] creatSql = metadata.getDatabase().getDialect().getTableExporter().getSqlCreateStrings(table, metadata);
                List<String> sqlList = new ArrayList<>();
                for (String item : creatSql) {
                    String sql = "";
                    if (StringUtils.isNotBlank(item)) {
                        if (info.getDbType() == DbType.PgSQL || info.getDbType() == DbType.HighGo || info.getDbType() == DbType.OpenGauss) {
                            sql = item.replace('\"' + table.getSchema() + '\"' + "." + table.getName(), table.getName());
                            sql = sql.replaceAll("(?i)TABLE", "TEMP TABLE") + " ON COMMIT PRESERVE ROWS";
                        }
                        if (info.getDbType() == DbType.SQLServer) {
                            sql = item.replace("[" + table.getCatalog() + "]" + "." + "[" + table.getSchema() + "]" + "." + table.getName(), "#" + table.getName());
                        }
                        if (info.getDbType() == DbType.Oracle || info.getDbType() == DbType.Oscar || info.getDbType() == DbType.Kingbase) {
                            sql = item.replace('\"' + table.getSchema() + '\"' + "." + table.getName(), table.getName());
                            sql = sql.replaceAll("(?i)TABLE", "GLOBAL TEMPORARY TABLE") + " ON COMMIT PRESERVE ROWS";
                        }
                        if (info.getDbType() == DbType.DM) {
                            sql = item.replace('\"' + table.getSchema() + '\"' + "." + table.getName(), table.getName());
                            sql = sql.replaceAll("(?i)TABLE", "GLOBAL TEMPORARY TABLE") + " ON COMMIT PRESERVE ROWS";
                        }
                        if (info.getDbType() == DbType.MySQL) {
                            sql = item.replace('\"' + table.getSchema() + '\"' + "." + table.getName(), table.getName());
                            sql = sql.replaceAll("(?i)TABLE", "TEMPORARY TABLE IF NOT EXISTS");
                        }
                        if (info.getDbType() == DbType.DB2) {
                            sql = item.replace('\"' + table.getSchema() + '\"' + "." + table.getName(), table.getName());
                            sql = sql.replaceAll("(?i)TABLE", "GLOBAL TEMPORARY TABLE") + " ON COMMIT PRESERVE ROWS";
                        }

                        if (StringUtils.isNotBlank(sql)) {
                            log.info("临时表创建SQL：" + sql);
                            sqlList.add(sql);
                        }
                    }
                }
                final Iterator<Index> indexItr = table.getIndexIterator();
                while (indexItr.hasNext()) {
                    final Index index = indexItr.next();
                    if (!StringHelper.isEmpty(index.getName())) {
                        String[] indexSql = metadata.getDatabase().getDialect().getIndexExporter().getSqlCreateStrings(index, metadata);
                        for (String item : indexSql) {
                            if (StringUtils.isNotBlank(item)) {
                                item = item.replace('\"' + table.getSchema() + '\"' + "." + table.getName(), table.getName());
                                log.info("索引创建SQL：" + item);
                                sqlList.add(item);
                            }
                        }
                    }
                }
                sqlMap.put(table.getName().toLowerCase(), sqlList);
            }
            return sqlMap;
        } catch (Exception e) {
            throw new RuntimeException("获取临时表创建SQL出错：", e);
        } finally {
            closeSessionFactory();
            DboDeployFileService fileService = new DboDeployFileService();
            fileService.deleteJavaFile(runtimePath, generatorPath);
        }
    }

    private void monthDboDeployInit(List<AbstractDatabaseObject> databaseObjects, List<String> tables) {
        DatabaseObjectTable table;
        AbstractDatabaseObject localDatabaseObject;
        HashMap<String, AbstractDatabaseObject> dbos = getDboFromDb(databaseObjects, dbInfo);
        DatabaseObjectCommonUtil commonUtil = new DatabaseObjectCommonUtil();
        for (AbstractDatabaseObject databaseObject : databaseObjects) {
            DboTableChangeInfo dboTableChangeInfo=null;
            localDatabaseObject = dbos.get(databaseObject.getId());
            List<String> currentDbTables = tables.stream().filter(x -> x.toLowerCase().startsWith(databaseObject.getCode().toLowerCase()) && x.length() == databaseObject.getCode().length() + 4).collect(Collectors.toList());
            if (currentDbTables.size() > 0) {
                dboTableChangeInfo = commonUtil.getDboTableChangeInfo(databaseObject, localDatabaseObject);
                localDatabaseObject = commonUtil.mergeDboIncrement(dboTableChangeInfo, localDatabaseObject, databaseObject);
                for (String dbTable : currentDbTables) {
                    Map<String, String> dimension = new HashMap<>();
                    dimension.put("YYMM", dbTable.substring(databaseObject.getCode().length()));
                    table = changeTableInfo(((DatabaseObjectTable) localDatabaseObject).clone(), dimension);
                    //处理字段修改为多语
                    if (dboTableChangeInfo.getChangedColumn() != null && dboTableChangeInfo.getNewMulityLanguageColumns() != null && dboTableChangeInfo.getNewMulityLanguageColumns().size() > 0) {
                        List<String> sql = getMultiLanguageSql(table, dboTableChangeInfo);
                        for (String current : sql) {
                            if (!SqlList.contains(current)) {
                                SqlList.addAll(sql);
                            }
                        }
                    }
                    //列详细的修改动作
                    columnChangeOperations.put(table.getCode(), dboTableChangeInfo.getChangedColumnOperations());
                    columnChangedTables.put(table.getCode(), table);
                    List<String> updateSql = getUpdateColumnSql(table,dboTableChangeInfo);
                    SqlList.addAll(updateSql);
                    String fileName = table.getCode() + UUID.randomUUID().toString().substring(0, 5);
                    dboClasses.add(fileName);
                    deployDatabaseObject(table, fileName, dboClasses.get(0));
                }
                newDatabaseObjects.add(localDatabaseObject);
            } else {
                table = changeTableInfo(((DatabaseObjectTable) databaseObject).clone(), null);
                newDatabaseObjects.add(databaseObject);
                newTable.add(table);

                String fileName = table.getCode() + UUID.randomUUID().toString().substring(0, 5);
                dboClasses.add(fileName);
                deployDatabaseObject(table, fileName, dboClasses.get(0));
            }
        }
    }

    /**
     * DBO部署参数初始
     *
     * @param databaseObjects 数据库对象列表
     * @param dimensionInfo   维度信息
     */
    private void dbosDeployInit(List<AbstractDatabaseObject> databaseObjects, Map<String, String> dimensionInfo, List<String> tables) {
        if (databaseObjects == null) {
            throw new DboException("部署的数据库对象列表不能为null！");
        }
        for (AbstractDatabaseObject object : databaseObjects) {
            if (object == null) {
                throw new DboException("部署的数据库对象列表中不能包含null！");
            }
        }
        DatabaseObjectCheckUtil checkUtil = new DatabaseObjectCheckUtil();
        DatabaseObjectCommonUtil commonUtil = new DatabaseObjectCommonUtil();
        AbstractDatabaseObject localDatabaseObject = null;
        if (tables == null || tables.size() == 0) {
            tables = commonUtil.getDbTables(dbInfo);
        }
        HashMap<String, AbstractDatabaseObject> dbos = getDboFromDb(databaseObjects, dbInfo);
        DatabaseObjectTable table = null;
        boolean isNewTable = false;
        for (AbstractDatabaseObject databaseObject : databaseObjects) {
            DboTableChangeInfo dboTableChangeInfo = null;
            checkUtil.checkDatabaseObjectAvailable(databaseObject);
            if (databaseObject.getType() == DatabaseObjectType.Table) {
                isNewTable = false;
                localDatabaseObject = dbos.get(databaseObject.getId());
                if (localDatabaseObject != null && isExistTable(tables, getTableName(databaseObject, dimensionInfo))) {
                    dboTableChangeInfo = commonUtil.getDboTableChangeInfo(databaseObject, localDatabaseObject);
                    localDatabaseObject = commonUtil.mergeDboIncrement(dboTableChangeInfo, localDatabaseObject, databaseObject);
                    table = ((DatabaseObjectTable) localDatabaseObject).clone();
                    newDatabaseObjects.add(localDatabaseObject);
                } else {
                    isNewTable = true;
                    table = ((DatabaseObjectTable) databaseObject).clone();
                    newDatabaseObjects.add(databaseObject);
                }
                table = changeTableInfo(table, dimensionInfo);
                if (isNewTable) {
                    newTable.add(table);
                } else {
                    //处理字段修改为多语
                    if (dboTableChangeInfo.getChangedColumn() != null && dboTableChangeInfo.getNewMulityLanguageColumns() != null && dboTableChangeInfo.getNewMulityLanguageColumns().size() > 0) {
                        List<String> sql = getMultiLanguageSql(table, dboTableChangeInfo);
                        for (String current : sql) {
                            if (!SqlList.contains(current)) {
                                SqlList.addAll(sql);
                            }
                        }
                    }
                    //列详细的修改动作
                    columnChangeOperations.put(table.getCode(), dboTableChangeInfo.getChangedColumnOperations());
                    columnChangedTables.put(table.getCode(), table);
                }
                String fileName = table.getCode() + UUID.randomUUID().toString().substring(0, 5);
                dboClasses.add(fileName);
                deployDatabaseObject(table, fileName, dboClasses.get(0));
                List<String> updateSql = getUpdateColumnSql(table,dboTableChangeInfo);
                SqlList.addAll(updateSql);
                if (table.isSynHis()) {
                    DatabaseObjectTable hisTable = table.clone();
                    hisTable.setCode(hisTable.getCode() + "_His");
                    //处理索引
                    for (DatabaseObjectIndex index : hisTable.getIndexes()
                    ) {
                        index.setCode(index.getCode() + "_His");
                    }
                    String hisTableFileName = hisTable.getCode() + UUID.randomUUID().toString().substring(0, 5);
                    dboClasses.add(hisTableFileName);
                    deployDatabaseObject(hisTable, hisTableFileName, dboClasses.get(0));

                    if (isNewTable) {
                        newTable.add(hisTable);
                    } else {
                        //列详细的修改动作
                        columnChangeOperations.put(table.getCode(), dboTableChangeInfo.getChangedColumnOperations());
                    }
                }
            }
            if (databaseObject.getType() == DatabaseObjectType.View) {
                newDatabaseObjects.add(databaseObject);
                DatabaseObjectView view = ((DatabaseObjectView) databaseObject).clone();
                List<String> sqlList = getViewSqls(view, dimensionInfo);
                if (sqlList != null && sqlList.size() > 0) {
                    SqlList.addAll(sqlList);
                }
            }
            //临时表只需要保持记录到gspdatabaseobject，不需要部署
            if (databaseObject.getType() == DatabaseObjectType.TempTable) {
                newDatabaseObjects.add(databaseObject);
            }
        }
    }

    private List<String> getUpdateColumnSql(DatabaseObjectTable table, DboTableChangeInfo dboTableChangeInfo) {
        List<String> sqls = new ArrayList<>();
        List<DatabaseObjectColumn> addColumns = new ArrayList<>();
        if(dboTableChangeInfo!=null){
            if(dboTableChangeInfo.getAddedColumn()!=null && dboTableChangeInfo.getAddedColumn().size()>0){
                addColumns.addAll(dboTableChangeInfo.getAddedColumn());
            }
        }
        if(DbType.SQLServer.equals(dbType) && addColumns !=null && addColumns.size()>0){
            for(DatabaseObjectColumn column:addColumns){
                List<String> multiColumns = table.getMultiLanguageColumns();
                if(multiColumns!=null && multiColumns.size()>0 && multiColumns.contains(column.getId())){
                    continue;
                }
                if(column.getDefaultValue()!=null && column.getDefaultValue()!=""){
                    sqls.add("update "+table.getCode()+ " set " + column.getCode() + " = " + "\'"+column.getDefaultValue()+"\'");
                }
            }
        }
        return sqls;
    }

    private boolean isExistTable(List<String> tables, String table) {
        for (String obj : tables) {
            if (obj.equalsIgnoreCase(table)) {
                return true;
            }
        }
        return false;
    }


    /**
     * 执行DBO部署
     *
     * @param dbInfo 数据库信息
     */
    private void dbosDeployExecute(DBInfo dbInfo) {

        //指定编译路径，支持多线程部署
        String generatorPath = "";
        try {
            runtimePath = System.getProperty("user.dir");

            if (dboClasses != null && dboClasses.size() > 0) {
                generatorPath = dboClasses.get(0);
                DboDeployFileService fileService = new DboDeployFileService();
                fileService.compile(newDatabaseObjects.get(0), dbType, dboClasses.get(0));
                fileService.loadClass(runtimePath, generatorPath);
            }
            try {
                doDeploy(dboClasses, SqlList);
                if (dbInfo.getDbType() == DbType.SQLServer) {
                    modifyTableClusteredPk(newTable, dbInfo);
                }
                //执行表结构的扩展修改逻辑，hibernate不支持的操作
                modifyTableExtend(dbInfo);
                saveDbo(newDatabaseObjects);
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                closeSessionFactory();
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            DboDeployFileService fileService = new DboDeployFileService();
            fileService.deleteJavaFile(runtimePath, generatorPath);
        }
    }

    private List<String> getMultiLanguageSql(DatabaseObjectTable table, DboTableChangeInfo changeInfo) {
        List<String> sqlList = new ArrayList<>();
        if (changeInfo.getChangedColumn() == null) {
            return sqlList;
        }
        String tableName = table.getCode();
        IDatabaseObjectSQLReflect manager = SQLReflectHelper.getInstance().GetManager(dbType.toString());
        for (String colId : changeInfo.getNewMulityLanguageColumns()) {

            List<DatabaseObjectColumn> columns = changeInfo.getChangedColumn().stream().filter(item -> item.getId().equals(colId)).collect(Collectors.toList());
            if (columns.size() > 0) {
                String oldColumn = columns.get(0).getCode();
                //默认将原有列重命名为_chs列
                String newColumn = oldColumn + "_chs";
                String dropSql = manager.getDropColumnSql(tableName, newColumn);
                String renameSql = manager.getReNameColumnSql(tableName, oldColumn, newColumn);
                DatabaseObjectCommonUtil commonUtil = new DatabaseObjectCommonUtil();
                if (commonUtil.isFiledExist(dbInfo, tableName, oldColumn)) {
                    sqlList.add(dropSql);
                    sqlList.add(renameSql);
                    if (dbInfo.getDbType() == DbType.DB2) {
                        //DB2每次alter表，必须执行REORG TABLE
                        String reorgSql = "CALL SYSPROC.ADMIN_CMD('REORG TABLE " + tableName + "')";
                        sqlList.add(reorgSql);
                    }
                }
            }

        }
        return sqlList;
    }

    private List<String> getViewSqls(DatabaseObjectView view, Map<String, String> dimensionInfo) {
        String viewName;

        if (view.getHasNameRule()) {
            viewName = getTableName(view.getCode(), view.getDboTableNameRule(), dimensionInfo);
        } else {
            viewName = view.getCode();
        }
        IDatabaseObjectSQLReflect relectmanager = SQLReflectHelper.getInstance().GetManager(dbType.toString());
        String viewdefination = "";
        if (view.getDefinationWithDbType() != null && view.getDefinationWithDbType().size() > 0) {
            ViewDefination defination = view.getDefinationWithDbType().stream().filter((item) -> item.getDbType().toLowerCase().equals(dbInfo.getDbType().toString().toLowerCase())).findFirst().orElse(null);
            if (defination != null && defination.getDefination() != null && defination.getDefination().length() > 0) {
                viewdefination = defination.getDefination();
            } else {
                viewdefination = view.getDefination();
            }
        } else {
            viewdefination = view.getDefination();
        }
        if (viewdefination.contains("@YR@")) {
            viewdefination = viewdefination.replace("@YR@", dimensionInfo.get("FIYear"));
        }
        if (viewdefination != null && viewdefination.length() > 0) {
            return relectmanager.GetViewSql(viewName, viewdefination);
        } else {
            return null;
        }
    }

    private DatabaseObjectTable changeTableInfo(DatabaseObjectTable table, Map<String, String> dimensionInfo) {
        List<DatabaseObjectIndex> indexes = table.getIndexes();
        Map<String,List<DatabaseObjectColumn>> columnMap = new HashMap<>();
        for(DatabaseObjectIndex index:indexes){
            columnMap.put(index.getId(),index.getColumns());
        }
        DatabaseObjectCheckUtil checkUtil = new DatabaseObjectCheckUtil();
        if (table.getHasNameRule()) {
            String name = getTableName(table.getCode(), table.getDboTableNameRule(), dimensionInfo);
            checkUtil.checkObjectCode(name);
            table.setCode(name);

            for (DatabaseObjectIndex index : table.getIndexes()
            ) {
                String indexName = getTableName(index.getCode(), table.getDboTableNameRule(), dimensionInfo);
                checkUtil.checkObjectCode(indexName);
                index.setCode(indexName);
            }
        }

        if (table.isI18NObject() && table.getMultiLanguageColumns() != null && table.getMultiLanguageColumns().size() > 0) {
            List<String> languages = DatabaseObjectCommonUtil.getLanguages();
            for (String columnId : table.getMultiLanguageColumns()) {
                DatabaseObjectColumn column = table.getColumnById(columnId);
                for(DatabaseObjectIndex index:indexes){
                    Optional<DatabaseObjectColumn> column1 =columnMap.get(index.getId()).stream().filter(t->t.getId().equals(column.getId())).findFirst();
                    if(column1.isPresent()){
                        for(DatabaseObjectColumn column2:index.getColumns()){
                            if(column1.get().getId().equals(column2.getId())){
                                String code = column2.getCode()+"_CHS";
                                String name = column2.getName()+"CHS";
                                column2.setCode(code);
                                column2.setName(name);
                            }
                        }
                    }
                }
                column.setNullable(true);
                column.setUnique(false);
                for (String language : languages) {
                    //如果DBO已经存在了多语字段，跳过
                    if (table.getColumnByCode(column.getCode() + language) != null) {
                        continue;
                    }
                    DatabaseObjectColumn clonedColumn = column.clone();
                    clonedColumn.setCode(column.getCode() + language);
                    clonedColumn.setNullable(true);
                    clonedColumn.setUnique(false);
                    table.getColumns().add(clonedColumn);
                }
                //新增多语字段，原字段不需要；修改为多语字段，需要使用SQL进行Rename，不在此处处理
                table.getColumns().remove(column);
            }
        }
        if (table.isUsingTimeStamp()) {
            ArrayList<DatabaseObjectColumn> columns = ReservedColumns.getTimeStampColumns();
            table.getColumns().addAll(columns);
        }
        return table;
    }

    private void applySetting() {
        serviceRegistryBuilder = new StandardServiceRegistryBuilder();
        serviceRegistryBuilder.applySetting("hibernate.show_sql", "false");
        serviceRegistryBuilder.applySetting("hibernate.format_sql", "true");
        serviceRegistryBuilder.applySetting("hibernate.use_sql_comments", "true");
        serviceRegistryBuilder.applySetting("schemaUpdate", "true");
        serviceRegistryBuilder.applySetting("hibernate.hbm2ddl.auto", "update");
        serviceRegistryBuilder.applySetting("spring.jpa.hibernate.ddl-auto", "update");
        serviceRegistryBuilder.applySetting("hibernate.connection.autocommit", "true");
        serviceRegistryBuilder.applySetting("hibernate.current_session_context_class", "thread");
        serviceRegistryBuilder.applySetting("hibernate.temp.use_jdbc_metadata_defaults", "false");
        serviceRegistryBuilder.applySetting("hibernate.connection.url", dbInfo.getUrl());
        serviceRegistryBuilder.applySetting("hibernate.connection.username", dbInfo.getUserName());
        serviceRegistryBuilder.applySetting("hibernate.connection.password", dbInfo.getPassWord());
        serviceRegistryBuilder.applySetting("hibernate.synonyms", true);

        //修改为springboot启动后，必须加上default_schema，SqlServer下还需要default_catalog
        if (dbType == DbType.PgSQL) {
            serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getUserName() + "]");
            serviceRegistryBuilder.applySetting("hibernate.connection.driver_class", "org.postgresql.Driver");
            serviceRegistryBuilder.applySetting("hibernate.dialect", "org.hibernate.dialect.PostgreSQL95Dialect");
        } else if (dbType == DbType.SQLServer) {
            serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getUserName() + "]");
            serviceRegistryBuilder.applySetting("hibernate.default_catalog", "[" + dbInfo.getDbName() + "]");
            serviceRegistryBuilder.applySetting("hibernate.connection.driver_class", "com.microsoft.sqlserver.jdbc.SQLServerDriver");
            serviceRegistryBuilder.applySetting("hibernate.dialect", "org.hibernate.dialect.SQLServer2012Dialect");
        } else if (dbType == DbType.Oracle) {
            serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getUserName().toUpperCase() + "]");
            serviceRegistryBuilder.applySetting("hibernate.connection.driver_class", "oracle.jdbc.OracleDriver");
            serviceRegistryBuilder.applySetting("hibernate.dialect", "org.hibernate.dialect.Oracle12cDialect");
        } else if (dbType == DbType.DM) {
            serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getUserName().toUpperCase() + "]");
            serviceRegistryBuilder.applySetting("hibernate.connection.driver_class", "dm.jdbc.driver.DmDriver");
            serviceRegistryBuilder.applySetting("hibernate.dialect", "org.hibernate.dialect.DmDialect");
        } else if (dbType == DbType.HighGo) {
            serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getUserName() + "]");
            serviceRegistryBuilder.applySetting("hibernate.connection.driver_class", "com.highgo.jdbc.Driver");
            serviceRegistryBuilder.applySetting("hibernate.dialect", "org.hibernate.dialect.HgdbDialect");
        } else if (dbType == DbType.MySQL) {
            //serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getDbName() + "]");
            serviceRegistryBuilder.applySetting("hibernate.default_catalog", "[" + dbInfo.getDbName() + "]");
            serviceRegistryBuilder.applySetting("hibernate.connection.driver_class", "com.mysql.cj.jdbc.Driver");
            serviceRegistryBuilder.applySetting("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect");
        } else if (dbType == DbType.Oscar) {
            //serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getDbName() + "]");
            serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getUserName().toUpperCase() + "]");
            serviceRegistryBuilder.applySetting("hibernate.connection.driver_class", "com.oscar.Driver");
            serviceRegistryBuilder.applySetting("hibernate.dialect", "org.hibernate.dialect.OscarDialect");
        } else if (dbType == DbType.Kingbase) {
            serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getUserName() + "]");
            serviceRegistryBuilder.applySetting("hibernate.connection.driver_class", "com.kingbase8.Driver");
            serviceRegistryBuilder.applySetting("hibernate.dialect", "org.hibernate.dialect.Kingbase8Dialect");
        } else if (dbType == DbType.DB2) {
            serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getUserName().toUpperCase() + "]");
            serviceRegistryBuilder.applySetting("hibernate.connection.driver_class", "com.ibm.db2.jcc.DB2Driver");
            serviceRegistryBuilder.applySetting("hibernate.dialect", "org.hibernate.dialect.DB2Dialect");
        } else if (dbType == DbType.OpenGauss) {
            serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getUserName() + "]");
            serviceRegistryBuilder.applySetting("hibernate.connection.driver_class", "org.opengauss.Driver");
            serviceRegistryBuilder.applySetting("hibernate.dialect", "org.hibernate.dialect.PostgreSQL95Dialect");
        } else if (dbType == DbType.GBase8s) {
            serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getUserName() + "]");
            serviceRegistryBuilder.applySetting("hibernate.connection.driver_class", "cn.gbase8s.Driver");
            serviceRegistryBuilder.applySetting("hibernate.dialect", "org.hibernate.dialect.PostgreSQL95Dialect");
        } else if (dbType == DbType.GBase8c) {
            serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getUserName() + "]");
            serviceRegistryBuilder.applySetting("hibernate.connection.driver_class", "cn.gbase8c.Driver");
            serviceRegistryBuilder.applySetting("hibernate.dialect", "org.hibernate.dialect.PostgreSQL95Dialect");
        }
    }

    private String getTableName(AbstractDatabaseObject databaseObject, Map<String, String> dimensionInfo) {
        String tableName = databaseObject.getCode();
        if (databaseObject.getType() == DatabaseObjectType.Table) {
            DatabaseObjectTable table = (DatabaseObjectTable) databaseObject;
            if (table.getHasNameRule()) {
                tableName = getTableName(table.getCode(), table.getDboTableNameRule(), dimensionInfo);
            }
        } else if (databaseObject.getType() == DatabaseObjectType.View) {
            DatabaseObjectView view = (DatabaseObjectView) databaseObject;
            tableName = getTableName(view.getCode(), view.getDboTableNameRule(), dimensionInfo);
        }
        return tableName;
    }


    private String getTableName(String dboCode, DBOTableNameRule tableNameRule, Map<String, String> dimensionInfo) {
        ITableNameRuleManager rtmanager;
        try {
            rtmanager = TableNameHelper.getInstance().GetManager(tableNameRule.getId());
        } catch (Exception e) {
            throw new RuntimeException("获取表名规则扩展实现配置报错，表名规则为：" + tableNameRule.getId());
        }
        if (rtmanager == null) {
            throw new DboException("未获取到表名规则扩展实现，表名规则为：" + tableNameRule.getId());
        }
        String tableName = rtmanager.getTableName(dboCode, tableNameRule, dimensionInfo);
        DatabaseObjectCheckUtil checkUtil = new DatabaseObjectCheckUtil();
        checkUtil.checkObjectCode(tableName);

        return tableName;
    }

    private void deployDatabaseObject(AbstractDatabaseObject databaseObject, String fileName, String generatorPath) {
        DboDeployFileService fileService = new DboDeployFileService();
        fileService.gernerateClass(databaseObject, dbType, fileName, generatorPath);
    }

    private void doDeploy(List<String> dboClasses, List<String> sqlList) throws ClassNotFoundException {

        ServiceRegistry serviceRegistry = serviceRegistryBuilder.build();
        MetadataSources metadataSources = new MetadataSources(serviceRegistry);
        metadataSources.addAnnotatedClass(GspDatabaseObject.class);
        for (String dboClass : dboClasses) {
            Class b = Class.forName("dbo." + dboClass);
            metadataSources.addAnnotatedClass(b);
        }
        MetadataBuilder metadataBuilder = metadataSources.getMetadataBuilder();
        //在真正执行部署时，需要再次指定表名规则，否则不生效
        DboPhysicalNamingStrategy dboPhysicalNamingStrategy =new DboPhysicalNamingStrategy();
        dboPhysicalNamingStrategy.setDbType(dbType);
        metadataBuilder.applyPhysicalNamingStrategy(dboPhysicalNamingStrategy);
        metadata = metadataBuilder.build();
        //同步表结构出错hibernate只抛出warn，需要手工捕获
        //catchSqlWarn();
        sessionFactory = metadata.buildSessionFactory();
        if (sqlList != null && sqlList.size() > 0) {
            String currentSql = "";
            try (Session session = sessionFactory.getCurrentSession()) {
                Transaction tx = session.beginTransaction();
                for (String sql : sqlList) {
                    currentSql = sql;
                    NativeQuery query = session.createSQLQuery(sql);
                    log.info("执行SQL：" + sql);
                    query.executeUpdate();
                }
                tx.commit();
            } catch (Exception e) {
                throw new RuntimeException("执行SQL出错，SQL语句为：" + currentSql, e);
            }
        }
    }

    private void saveDbo(List<AbstractDatabaseObject> databaseObjects) {
        try (Session session = sessionFactory.getCurrentSession()) {
            Transaction tx = session.beginTransaction();
            for (AbstractDatabaseObject databaseObject : databaseObjects) {
                GspDatabaseObject gspDatabaseObject = session.get(GspDatabaseObject.class, databaseObject.getId());
                gspDatabaseObject = buildGspDatabaseObject(databaseObject, gspDatabaseObject);
                session.saveOrUpdate(gspDatabaseObject);
                DatabaseObjectCacheManager.getInstance().removeDatabaseObjectContent(databaseObject.getId());
            }
            tx.commit();
        }
    }

    /**
     * 修改SqlServer数据库表主键的聚集索引为非聚集索引
     */
    private void modifyTableClusteredPk(List<AbstractDatabaseObject> databaseObjects, DBInfo dbInfo) {
        String constraintName = null;
        String tableName = null;
        String sql = null;
        NativeQuery query = null;
        Object queryResult = null;
        DatabaseObjectTable databaseObjectTable = null;
        try (Session session = sessionFactory.getCurrentSession()) {
            Transaction tx = session.beginTransaction();
            for (AbstractDatabaseObject databaseObject : databaseObjects) {
                tableName = databaseObject.getCode();
                //查询主键约束
                sql = "select name from sys.key_constraints where type='PK' and parent_object_id in (select id from sysobjects where name='" + tableName + "')";
                query = session.createSQLQuery(sql);
                if (query.getResultList().size() == 0) {
                    continue;
                }
                queryResult = query.getSingleResult();
                if (queryResult == null) {
                    continue;
                }
                constraintName = (String) queryResult;
                //drop主键约束
                sql = "alter table " + tableName + " drop constraint " + constraintName;
                query = session.createSQLQuery(sql);
                query.executeUpdate();
                //添加主键
                databaseObjectTable = (DatabaseObjectTable) databaseObject;
                // constraintName = databaseObjectTable.getPkName();
                if (constraintName == null || constraintName.length() == 0)
                    constraintName = "Pk_" + tableName + UUID.randomUUID().toString().substring(0, 3);
                List<String> keys = databaseObjectTable.getPrimaryKey();
                String keyCloumnStr = "(";
                if (keys != null && keys.size() > 0) {
                    for (String key : keys) {
                        keyCloumnStr = keyCloumnStr + databaseObjectTable.getColumnById(key).getCode() + ",";
                    }
                    keyCloumnStr = keyCloumnStr.substring(0, keyCloumnStr.length() - 1);
                    keyCloumnStr = keyCloumnStr + ")";
                } else {
                    keyCloumnStr = "(id)";
                }
                sql = "alter table " + tableName + " add constraint " + constraintName + " primary key NONCLUSTERED" + keyCloumnStr;
                query = session.createSQLQuery(sql);
                query.executeUpdate();
            }
            tx.commit();
        }
    }

    /**
     * 表结构扩展修改，hibernate不支持的修改
     *
     * @param db 数据库信息
     */
    private void modifyTableExtend(DBInfo db) {
        if (columnChangeOperations == null || columnChangeOperations.isEmpty()) {
            return;
        }
        SqlProvider sqlProvider = new SqlProvider();
        List<String> allColumnSqls;
        List<String> oneColumnSqls;
        String table;
        DatabaseObjectTable databaseObjectTable = null;
        List<ColumnChangeOperation> columnChangeOperationList;
        List<String> languages = DatabaseObjectCommonUtil.getLanguages();
        for (Map.Entry<String, List<ColumnChangeOperation>> entry : columnChangeOperations.entrySet()) {
            table = entry.getKey();
            databaseObjectTable = columnChangedTables.get(table);
            columnChangeOperationList = entry.getValue();
            if (columnChangeOperationList == null || columnChangeOperationList.size() == 0) {
                continue;
            }
            allColumnSqls = new ArrayList<>();
            for (ColumnChangeOperation operation : columnChangeOperationList) {
                oneColumnSqls = sqlProvider.providerSql(table, databaseObjectTable, languages, operation, db, serviceRegistryBuilder, metadata);
                if (oneColumnSqls.size() == 0) {
                    continue;
                }
                allColumnSqls.addAll(oneColumnSqls);
            }
            if (allColumnSqls.size() == 0) {
                continue;
            }
            //pg、highgo数据库，需要先移除视图依赖
            List<String> depViews = null;
            if (db.getDbType() == DbType.PgSQL || db.getDbType() == DbType.HighGo || db.getDbType() == DbType.OpenGauss) {
                if (views == null) {
                    views = getViews(db);
                }
                log.info("pg数据库,移除依赖表[" + table + "]的视图");
                depViews = findDependentViews(table, depViews);
                dropDependentViews(depViews);
            }
            //执行修改列sql
            exeSqls(allColumnSqls);
            //pg、highgo数据库,创建上依赖的视图
            if (db.getDbType() == DbType.PgSQL || db.getDbType() == DbType.HighGo || db.getDbType() ==DbType.OpenGauss) {
                createDependentViews(depViews);
            }
        }
    }

    private void dropDependentViews(List<String> views) {
        if (views == null || views.size() == 0) {
            return;
        }
        List<String> dropSqls = new ArrayList<>();
        List<String> collect = new ArrayList<>();
        collect.addAll(views);
        Collections.reverse(collect);
        String sql;
        for (String view : collect) {
            sql = "DROP VIEW IF EXISTS " + view;
            dropSqls.add(sql);
        }
        exeSqls(dropSqls);
    }

    private void createDependentViews(List<String> views) {
        if (views == null || views.size() == 0) {
            return;
        }
        List<String> createSqls = new ArrayList<>();
        String sql;
        String viewDefinition = null;
        for (String view : views) {
            viewDefinition = this.views.get(view).replace("::", "\\:\\:");
            sql = "CREATE VIEW " + view + System.lineSeparator() + "as" + System.lineSeparator() + viewDefinition;
            createSqls.add(sql);
        }
        exeSqls(createSqls);
    }

    private void exeSqls(List<String> sqls) {
        NativeQuery query;
        String currentSQL = "";
        try (Session session = sessionFactory.getCurrentSession()) {
            Transaction tx = session.beginTransaction();
            for (String sql : sqls) {
                currentSQL = sql;
                log.info("执行SQL：" + currentSQL);
                query = session.createSQLQuery(sql);
                query.executeUpdate();
            }
            tx.commit();
        } catch (Exception e) {
            throw new RuntimeException("执行SQL报错，报错SQL为：" + currentSQL, e);
        }
    }

    /**
     * 获取表被依赖的视图，需要考虑视图还被其它的视图依赖
     *
     * @param table
     * @return
     */
    private List<String> findDependentViews(String table, List<String> depViews) {
        if (depViews == null) {
            depViews = new ArrayList<>();
        }
       /* if (depViews.contains(table) && depViews.size() >=2) {
            return depViews;
        }*/
        for (Map.Entry<String, String> view : views.entrySet()) {
            if (table.equalsIgnoreCase(view.getKey())) {
                continue;
            }
            if (view.getValue().toLowerCase().contains(table.toLowerCase())) {
                if (depViews.contains(view.getKey())) {
                    depViews.remove(view.getKey());
                }
                depViews.add(view.getKey());
                depViews = findDependentViews(view.getKey(), depViews);
            }
        }
        return depViews;
    }


    /**
     * 获取数据库中的视图列表
     *
     * @return 返回视图列表
     */
    private Map<String, String> getViews(DBInfo db) {
        String sql = "select viewname,definition from pg_views where lower(schemaname)='" + db.getUserName().toLowerCase() + "'";
        NativeQuery query;
        Map<String, String> views = new HashMap<>();
        try (Session session = sessionFactory.getCurrentSession()) {
            Transaction tx = session.beginTransaction();
            query = session.createSQLQuery(sql);
            List<Object[]> result = query.getResultList();
            for (Object[] obj : result) {
                views.put(obj[0].toString(), obj[1].toString());
            }
            tx.commit();
        }
        return views;
    }

    /**
     * 根据dboId，获取数据库中的Dbo对象
     *
     * @param
     * @return
     */
    private HashMap<String, AbstractDatabaseObject> getDboFromDb(List<AbstractDatabaseObject> databaseObjects, DBInfo dbInfo) {
        if (databaseObjects == null || databaseObjects.size() == 0) {
            return new HashMap<>();
        }
        String inSql = "(";
        boolean flag=databaseObjects.size()>1000?true:false;
        int count=0;
        for (AbstractDatabaseObject databaseObject : databaseObjects) {
            if (databaseObject.getType() != DatabaseObjectType.Table) {
                continue;
            }
            if(++count%1000==0 && flag==true){
                inSql = inSql + "'" + databaseObject.getId() + "')" + " and id in (";
            }else{
                inSql = inSql + "'" + databaseObject.getId() + "',";
            }
        }
        if (inSql.equalsIgnoreCase("(")) {
            return new HashMap<String, AbstractDatabaseObject>();
        }
        inSql = inSql.substring(0, inSql.length() - 1);
        inSql = inSql + ")";
        GspDatabase db = GspDbFactory.getDatabase(dbInfo);
        String sql = "select id,content from gspdatabaseobject where id in" + inSql;
        ResultSet resultSet = null;
        String content = null;
        String id = null;
        HashMap<String, AbstractDatabaseObject> dbos = new HashMap<>();
        DatabaseObjectCommonUtil commonUtil = new DatabaseObjectCommonUtil();
        try {
            resultSet = db.executeResultSet(sql);
            if (resultSet != null) {
                while (resultSet.next()) {
                    id = resultSet.getString(1);
                    content = resultSet.getString(2);
                    AbstractDatabaseObject databaseObject = null;
                    try {
                        databaseObject = commonUtil.deserialze(DatabaseObjectType.Table, content);
                        if (!dbos.containsKey(id)) {
                            dbos.put(id, databaseObject);
                        }
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        } catch (SQLException e) {
            throw new RuntimeException("获取数据库DBO出错：", e);
        } finally {
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (db != null) {
                db.close();
            }
        }

        return dbos;
    }

    /**
     * 初始化SessionFactory
     */
    private void initSessionFactory() {
        ServiceRegistry serviceRegistry = serviceRegistryBuilder.build();
        MetadataSources metadataSources = new MetadataSources(serviceRegistry);
        metadataSources.addAnnotatedClass(GspDatabaseObject.class);
        MetadataBuilder metadataBuilder = metadataSources.getMetadataBuilder();
        DboPhysicalNamingStrategy dboPhysicalNamingStrategy = new DboPhysicalNamingStrategy();
        dboPhysicalNamingStrategy.setDbType(dbType);
        metadataBuilder.applyPhysicalNamingStrategy(dboPhysicalNamingStrategy);
        Metadata metadata = metadataBuilder.build();
        sessionFactory = metadata.buildSessionFactory();
    }

    /**
     * 关闭SessionFactory
     */
    private void closeSessionFactory() {
        if (sessionFactory != null) {
            sessionFactory.close();
        }
    }

    private static GspDatabaseObject buildGspDatabaseObject(AbstractDatabaseObject databaseObject, GspDatabaseObject gspDatabaseObject) {
        if (gspDatabaseObject == null) {
            gspDatabaseObject = new GspDatabaseObject();
            gspDatabaseObject.setId(databaseObject.getId());
            gspDatabaseObject.setCreatedTime(LocalDateTime.now());
            gspDatabaseObject.setType(databaseObject.getType().getValue());
        }

        gspDatabaseObject.setCode(databaseObject.getCode());
        gspDatabaseObject.setName(databaseObject.getName());
        if (databaseObject.getType() == DatabaseObjectType.Table || databaseObject.getType() == DatabaseObjectType.TempTable) {
            DatabaseObjectTable table = (DatabaseObjectTable) databaseObject;
            gspDatabaseObject.setBusinessObjectId(table.getBusinessObjectId());
            gspDatabaseObject.setIsI18NObject(table.isI18NObject() ? "1" : "0");
            if (table.getTenantIdentityColumn() != null) {
                gspDatabaseObject.setTenantIDColumnCode(table.getTenantIdentityColumn().getCode());
            }
            gspDatabaseObject.setIsFiscalTable("0");
            if (table.getHasNameRule()) {
                gspDatabaseObject.setRuleId(table.getDboTableNameRule().getId());
                gspDatabaseObject.setRuleCode(table.getDboTableNameRule().getCode());
            }
        } else {
            DatabaseObjectView view = (DatabaseObjectView) databaseObject;
            gspDatabaseObject.setBusinessObjectId(view.getBusinessObjectId());
            gspDatabaseObject.setIsI18NObject("0");
            gspDatabaseObject.setIsFiscalTable("0");
            if (view.getHasNameRule()) {
                gspDatabaseObject.setRuleId(view.getDboTableNameRule().getId());
                gspDatabaseObject.setRuleCode(view.getDboTableNameRule().getCode());
            }
        }

        gspDatabaseObject.setVersion(databaseObject.getVersion());
        gspDatabaseObject.setLastModifiedTime(LocalDateTime.now());
        DatabaseObjectCommonUtil commonUtil = new DatabaseObjectCommonUtil();
        try {
            gspDatabaseObject.setContent(commonUtil.serialze(databaseObject));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return gspDatabaseObject;
    }

    /**
     * 安装盘使用DBO部署接口
     *
     * @param dboPath        dbo路径
     * @param dimensionInfos 维度信息
     * @param dbInfo         数据库信息
     */
    public void deployDboWithDimensionListForDbSetup(String dboPath, Map<String, List<String>> dimensionInfos, DBInfo dbInfo) {
        DatabaseObjectServiceImpl service = new DatabaseObjectServiceImpl();
        List<AbstractDatabaseObject> databaseObjects = service.getDatabaseObjectListRecursivly(dboPath);

        List<Map<String, String>> list = new ArrayList<>();
        for (String key : dimensionInfos.keySet()) {
            list = getSingleMap(list, key, dimensionInfos.get(key));
        }

        dboClasses = new ArrayList<>();
        SqlList = new ArrayList<>();
        newDatabaseObjects = new ArrayList<>();
        newTable = new ArrayList<>();
        this.dbInfo = dbInfo;
        this.dbType = dbInfo.getDbType();
        applySetting();

        DatabaseObjectCommonUtil commonUtil = new DatabaseObjectCommonUtil();
        List<String> tables = commonUtil.getDbTables(dbInfo);
        //判断是否包含月度表
        List<AbstractDatabaseObject> monthDboList = databaseObjects.stream().filter(x -> x.getType() == DatabaseObjectType.Table && ((DatabaseObjectTable) x).getHasNameRule() && ((DatabaseObjectTable) x).getDboTableNameRule().getCode().equalsIgnoreCase("YYMM")).collect(Collectors.toList());
        if (monthDboList.size() > 0) {
            List<String> dboIds = monthDboList.stream().map(AbstractDatabaseObject::getId).collect(Collectors.toList());
            databaseObjects.removeIf(x -> dboIds.contains(x.getId()));
            monthDboDeployInit(monthDboList, tables);
        }

        for (Map<String, String> dimensionInfo : list) {
            dbosDeployInitForDbSetup(databaseObjects, dimensionInfo);
        }
        dbosDeployExecuteForDbSetup(dbInfo);
    }

    private void dbosDeployInitForDbSetup(List<AbstractDatabaseObject> databaseObjects, Map<String, String> dimensionInfo) {
        DatabaseObjectCheckUtil checkUtil = new DatabaseObjectCheckUtil();
        DatabaseObjectTable table = null;
        for (AbstractDatabaseObject databaseObject : databaseObjects) {
            checkUtil.checkDatabaseObjectAvailable(databaseObject);
            if (databaseObject.getType() == DatabaseObjectType.Table) {
                table = ((DatabaseObjectTable) databaseObject).clone();
                newDatabaseObjects.add(databaseObject);
                table = changeTableInfo(table, dimensionInfo);
                newTable.add(table);
                String fileName = table.getCode() + UUID.randomUUID().toString().substring(0, 5);
                dboClasses.add(fileName);
                deployDatabaseObject(table, fileName, dboClasses.get(0));
                if (table.isSynHis()) {
                    DatabaseObjectTable hisTable = table.clone();
                    hisTable.setCode(hisTable.getCode() + "_His");
                    //处理索引
                    for (DatabaseObjectIndex index : hisTable.getIndexes()
                    ) {
                        index.setCode(index.getCode() + "_His");
                    }
                    String hisTableFileName = hisTable.getCode() + UUID.randomUUID().toString().substring(0, 5);
                    dboClasses.add(hisTableFileName);
                    deployDatabaseObject(hisTable, hisTableFileName, dboClasses.get(0));
                    newTable.add(hisTable);
                }
            }
            if (databaseObject.getType() == DatabaseObjectType.View) {
                newDatabaseObjects.add(databaseObject);
                DatabaseObjectView view = ((DatabaseObjectView) databaseObject).clone();
                List<String> sqlList = getViewSqls(view, dimensionInfo);
                if (sqlList != null && sqlList.size() > 0) {
                    SqlList.addAll(sqlList);
                }
            }
            if (databaseObject.getType() == DatabaseObjectType.TempTable) {
                newDatabaseObjects.add(databaseObject);
            }
        }
    }

    private void dbosDeployExecuteForDbSetup(DBInfo dbInfo) {

        //指定编译路径，支持多线程部署
        String generatorPath = "";
        try {
            runtimePath = System.getProperty("user.dir");
            if (dboClasses != null && dboClasses.size() > 0) {
                generatorPath = dboClasses.get(0);
                DboDeployFileService fileService = new DboDeployFileService();
                fileService.compile(newDatabaseObjects.get(0), dbType, dboClasses.get(0));
                fileService.loadClass(runtimePath, generatorPath);
            }
            try {
                doDeploy(dboClasses, SqlList);
                if (dbInfo.getDbType() == DbType.SQLServer) {
                    modifyTableClusteredPk(newTable, dbInfo);
                }
                saveDbo(newDatabaseObjects);
            } catch (Exception e) {
                throw new RuntimeException(e);
            } finally {
                closeSessionFactory();
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            DboDeployFileService fileService = new DboDeployFileService();
            fileService.deleteJavaFile(runtimePath, generatorPath);
        }
    }
}
